//
//  NestScroll.swift
//  Example
//
//  Created by remy on 2020/2/23.
//  Copyright © 2020 com.Risac. All rights reserved.
//

class NestScroll {
    private var rootOB: NSKeyValueObservation?
    private var subOB: NSKeyValueObservation?
    private var rootEnabled: Bool = true
    private var subEnabled: Bool = false
    private var lastPanOffsetYInRoot: CGFloat = 0.0
    public private(set) weak var root: NestScrollView?
    public private(set) weak var sub: UIScrollView?
    public var rootOffsetYMax: CGFloat = 0.0
    public var bouncesRootFirst: Bool = true
    
    deinit {
        rootOB = nil
        subOB = nil
    }

    // MARK: ios11以下版本会出现被监听者已释放kvo还存在从而crash的问题
    // KVO监听self会出现该问题,因此从外部传入
    public func nest(root: NestScrollView? = nil,
                     sub: UIScrollView,
                     options: NSKeyValueObservingOptions = [.new, .old]) {
        if let root = root {
            self.root = root
            rootOB = root.observe(\.contentOffset, options: [.new, .old]) { [weak self] in
                guard $1.newValue != $1.oldValue else { return }
                self?.rootScrollViewDidScroll($0)
            }
        }
        self.sub = sub
        subOB = sub.observe(\.contentOffset, options: options) { [weak self] in
            guard $1.newValue != $1.oldValue else { return }
            self?.subScrollViewDidScroll($0)
        }
    }
    
    private func rootScrollViewDidScroll(_ root: UIScrollView) {
        let rootOffsetYMin = -root.contentInset.top
        let rootOffsetY = root.contentOffset.y
        if bouncesRootFirst {
            if !rootEnabled {
                root.contentOffset.y = rootOffsetYMax
                subEnabled = true
            } else if rootOffsetY >= rootOffsetYMax {
                root.contentOffset.y = rootOffsetYMax
                rootEnabled = false
                subEnabled = true
            }
        } else {
            // 手势移动距离,用于判断移动方向,和视图移动距离可能不同不能取contentOffset.y
            let panOffsetYInRoot = -root.panGestureRecognizer.translation(in: root).y.rounded(.up)
            if !rootEnabled {
                // 1.root固定max,sub解锁
                root.contentOffset.y = rootOffsetYMax
                subEnabled = true
            } else if rootOffsetY >= rootOffsetYMax {
                // 2.向上滑动,root偏移>=max,sub偏移>=min,root锁定,sub解锁
                rootEnabled = false
                subEnabled = true
            } else if rootOffsetY <= rootOffsetYMin {
                // 3.向下滑动,root偏移<=min固定min,sub偏移<=min,sub解锁
                root.contentOffset.y = rootOffsetYMin
                subEnabled = true
            } else {
                // 4-1:向上滑动,root偏移<max在max-min内向max移动
                // 4-2:向下滑动,root偏移>min在max-min内向min移动
                guard let sub = sub else { return }
                let subOffsetY = sub.contentOffset.y
                let subOffsetYMin = -sub.contentInset.top
                if subOffsetY < subOffsetYMin {
                    // sub偏移<min
                    if panOffsetYInRoot > lastPanOffsetYInRoot {
                        // 4-1情况下,sub偏移<min仍然保持3情况
                        root.contentOffset.y = rootOffsetYMin
                        subEnabled = true
                    } else {
                        // 4-2情况下,sub偏移<min,sub锁定
                        subEnabled = false
                    }
                } else {
                    // sub偏移>=min,sub锁定
                    subEnabled = false
                }
            }
            lastPanOffsetYInRoot = panOffsetYInRoot
        }
    }
    
    private func subScrollViewDidScroll(_ sub: UIScrollView) {
        let subOffsetYMin = -sub.contentInset.top
        let subOffsetY = sub.contentOffset.y
        if bouncesRootFirst {
            if !subEnabled {
                sub.contentOffset.y = subOffsetYMin
            } else if subOffsetY <= subOffsetYMin {
                rootEnabled = true
                subEnabled = false
            }
        } else {
            if !subEnabled {
                // sub固定min
                sub.contentOffset.y = subOffsetYMin
            } else if subOffsetY <= subOffsetYMin {
                // sub偏移<min,root解锁
                rootEnabled = true
            }
        }
    }
}

class NestScrollView: RisacScrollView, UIGestureRecognizerDelegate {
    // 是否识别多手势
    public var gesturesSimultaneously: Bool = true
    // 开启识别多手势时的例外手势
    public lazy var exceptGestures: [UIGestureRecognizer] = []
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        initView()
    }
    
    private func initView() {
        self.alwaysBounceVertical = true
    }
    
    public func setExceptGestures(_ gestures: [UIGestureRecognizer]?) {
        guard let gestures = gestures else {
            exceptGestures = []
            return
        }
        exceptGestures = gestures
    }
    
    public func addExceptGestures(_ gestures: [UIGestureRecognizer]?) {
        guard let gestures = gestures else { return }
        exceptGestures.append(contentsOf: gestures)
    }
    
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if gesturesSimultaneously {
            if exceptGestures.contains(otherGestureRecognizer) {
                return false
            }
            return true
        }
        return false
    }
}
